package net.qiqbframework.common.caching;



import net.qiqbframework.common.Registration;

import java.util.function.Supplier;
import java.util.function.UnaryOperator;


public interface Cache {


    <K, V> V get(K key);


    void put(Object key, Object value);


    boolean putIfAbsent(Object key, Object value);


    default <T> T computeIfAbsent(Object key, Supplier<T> valueSupplier) {
        Object currentValue = get(key);
        if (currentValue != null) {
            //noinspection unchecked
            return (T) currentValue;
        }
        T newValue = valueSupplier.get();
        if (newValue == null) {
            throw new IllegalArgumentException("Value Supplier of Cache produced a null value for key [" + key + "]!");
        }
        put(key, newValue);
        return newValue;
    }


    boolean remove(Object key);


    default void removeAll() {
        throw new UnsupportedOperationException("Cache#removeAll is currently unsupported by this version");
    }


    boolean containsKey(Object key);


    Registration registerCacheEntryListener(EntryListener cacheEntryListener);


    default <V> void computeIfPresent(Object key, UnaryOperator<V> update) {
        throw new UnsupportedOperationException("Cache#computeIfPresent is currently unsupported by this version");
    }


    interface EntryListener {


        void onEntryExpired(Object key);


        void onEntryRemoved(Object key);


        void onEntryUpdated(Object key, Object value);


        void onEntryCreated(Object key, Object value);


        void onEntryRead(Object key, Object value);


        Object clone() throws CloneNotSupportedException;
    }

    /**
     * Adapter implementation for the EntryListener, allowing for overriding only specific callback methods.
     */
    class EntryListenerAdapter implements EntryListener {

        @Override
        public void onEntryExpired(Object key) {
        }

        @Override
        public void onEntryRemoved(Object key) {
        }

        @Override
        public void onEntryUpdated(Object key, Object value) {
        }

        @Override
        public void onEntryCreated(Object key, Object value) {
        }

        @Override
        public void onEntryRead(Object key, Object value) {
        }

        @Override
        public Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
}
